//
//  YCPopUpMenu.m
//  DemoMenuMore
//
//  Created by 唐可雄 on 16/5/9.
//  Copyright © 2016年 swustyc. All rights reserved.
//

#import "YCPopUpMenu.h"

#import <QuartzCore/QuartzCore.h>

/// 箭头的大小
const CGFloat kArrowSize = 8.f;
const CGFloat kCellTitleFont = 15.f;
const CGFloat kCellHeight = 30.f;
const CGFloat kMinMask = 0.f;
const CGFloat kMaxMask = 0.5f;
const CGFloat kAnimationDuration = 0.3f;

#pragma mark - YCPopUpMenuItem

@implementation YCPopUpMenuItem

#pragma mark - Life Cycle

+ (instancetype)menuItem:(NSString *)title
                   image:(UIImage *)img
                  target:(id)targe
                  action:(SEL)action {
    return [[YCPopUpMenuItem alloc] init:title image:img target:targe action:action];
}

- (instancetype)init:(NSString *)title
               image:(UIImage *)img
              target:(id)target
              action:(SEL)action {
    // 校验数据
    NSParameterAssert(title.length || img);
    
    self = [super init];
    if (self) {
        self.title = title;
        self.img = img;
        self.target = target;
        self.action = action;
    }
    
    return self;
}

#pragma mark - Setter and Getter

/**
 *  根据操作对象和操作是否被实例化来判断是否可用
 *
 *  @return 是否可用
 */
- (BOOL)isEnable {
    return self.target != nil && self.action != NULL;
}

- (UIColor *)titleColor {
    if (!_titleColor) {
        return [UIColor whiteColor];
    }
    
    return _titleColor;
}

#pragma mark - Control

/**
 *  执行操作
 */
- (void)performAction {
    if ([self isEnable]) {
        if ([self.target respondsToSelector:self.action]) {
            [self.target performSelectorOnMainThread:self.action withObject:self waitUntilDone:YES];
        }
    }
}

@end

#pragma mark - YCPopUpMenuBgView

/**
 *  背景图箭头头像
 */
NS_OPTIONS(NSInteger, YCPopUpMenuBgViewArrowDirection){
    /**
     *  无方向
     */
    YCPopUpMenuBgViewArrowDirectionNone,
    /**
     *  向左
     */
    YCPopUpMenuBgViewArrowDirectionLeft,
    /**
     *  向右
     */
    YCPopUpMenuBgViewArrowDirectionRight,
    /**
     *  向上
     */
    YCPopUpMenuBgViewArrowDirectionUp,
    /**
     *  向下
     */
    YCPopUpMenuBgViewArrowDirectionDown
};

/**
 *  弹出菜单背景图
 */
@interface YCPopUpMenuBgView : UIView {
    CGFloat _arrowPosition;
}

@property (nonatomic, assign) enum YCPopUpMenuBgViewArrowDirection arrowDirection;
@property (nonatomic, assign) CGFloat arrowPosition;

@end

@implementation YCPopUpMenuBgView

#pragma mark - Setter and Getter

- (void)setArrowDirection:(enum YCPopUpMenuBgViewArrowDirection)arrowDirection {
    _arrowDirection = arrowDirection;
    
    [self setNeedsDisplay];
}

- (void)setArrowPosition:(CGFloat)arrowPosition {
    _arrowPosition = arrowPosition;
    
    [self setNeedsDisplay];
}

- (CGFloat)arrowPosition {
    return _arrowPosition;
}

#pragma mark - Draw

- (void)drawRect:(CGRect)rect {
    [self drawBackground:self.bounds
               inContext:UIGraphicsGetCurrentContext()];
}

/**
 *  绘制背景
 *
 *  @param frame   位置
 *  @param context 上下文
 */
- (void)drawBackground:(CGRect)frame
             inContext:(CGContextRef) context
{
    CGFloat R0 = 0.267, G0 = 0.303, B0 = 0.335;
    CGFloat R1 = 0.040, G1 = 0.040, B1 = 0.040;
    
    UIColor *tintColor = [self tintColor];
    if (tintColor) {
        CGFloat a;
        [tintColor getRed:&R0 green:&G0 blue:&B0 alpha:&a];
    }
    
    CGFloat X0 = frame.origin.x;
    CGFloat X1 = frame.origin.x + frame.size.width;
    CGFloat Y0 = frame.origin.y;
    CGFloat Y1 = frame.origin.y + frame.size.height;
    
    // 渲染箭头
    
    UIBezierPath *arrowPath = [UIBezierPath bezierPath];
    
    // 边框的
    const CGFloat kEmbedFix = 3.f;
    
    if (_arrowDirection == YCPopUpMenuBgViewArrowDirectionUp) {
        
        const CGFloat arrowX_Center = self.arrowPosition;
        const CGFloat arrowX0 = arrowX_Center - kArrowSize;
        const CGFloat arrowX1 = arrowX_Center + kArrowSize;
        const CGFloat arrowY0 = Y0;
        const CGFloat arrowY1 = Y0 + kArrowSize + kEmbedFix;
        
        [arrowPath moveToPoint:    (CGPoint){arrowX_Center, arrowY0}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
        [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY1}];
        [arrowPath addLineToPoint: (CGPoint){arrowX_Center, arrowY0}];
        
        [[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
        
        Y0 += kArrowSize;
        
    } else if (_arrowDirection == YCPopUpMenuBgViewArrowDirectionDown) {
        
        const CGFloat arrowX_Center = self.arrowPosition;
        const CGFloat arrowX0 = arrowX_Center - kArrowSize;
        const CGFloat arrowX1 = arrowX_Center + kArrowSize;
        const CGFloat arrowY0 = Y1 - kArrowSize - kEmbedFix;
        const CGFloat arrowY1 = Y1;
        
        [arrowPath moveToPoint:    (CGPoint){arrowX_Center, arrowY1}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
        [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY0}];
        [arrowPath addLineToPoint: (CGPoint){arrowX_Center, arrowY1}];
        
        [[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
        
        Y1 -= kArrowSize;
        
    } else if (_arrowDirection == YCPopUpMenuBgViewArrowDirectionLeft) {
        
        const CGFloat arrowY_Center = self.arrowPosition;
        const CGFloat arrowX0 = X0;
        const CGFloat arrowX1 = X0 + kArrowSize + kEmbedFix;
        const CGFloat arrowY0 = arrowY_Center - kArrowSize;;
        const CGFloat arrowY1 = arrowY_Center + kArrowSize;
        
        [arrowPath moveToPoint:    (CGPoint){arrowX0, arrowY_Center}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
        [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY_Center}];
        
        [[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
        
        X0 += kArrowSize;
        
    } else if (_arrowDirection == YCPopUpMenuBgViewArrowDirectionRight) {
        
        const CGFloat arrowY_Center = self.arrowPosition;
        const CGFloat arrowX0 = X1;
        const CGFloat arrowX1 = X1 - kArrowSize - kEmbedFix;
        const CGFloat arrowY0 = arrowY_Center - kArrowSize;;
        const CGFloat arrowY1 = arrowY_Center + kArrowSize;
        
        [arrowPath moveToPoint:    (CGPoint){arrowX0, arrowY_Center}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
        [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
        [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY_Center}];
        
        [[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
        
        X1 -= kArrowSize;
    }
    
    [arrowPath fill];
    
    // 渲染其他部分
    
    const CGRect bodyFrame = {X0, Y0, X1 - X0, Y1 - Y0};
    
    UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:bodyFrame
                                                          cornerRadius:5.f];
    
    const CGFloat locations[] = {0, 1};
    const CGFloat components[] = {
        R0, G0, B0, 1,
        R1, G1, B1, 1,
    };
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace,
                                                                 components,
                                                                 locations,
                                                                 sizeof(locations)/sizeof(locations[0]));
    CGColorSpaceRelease(colorSpace);
    
    
    [borderPath addClip];
    
    CGPoint start, end;
    
    if (_arrowDirection == YCPopUpMenuBgViewArrowDirectionLeft ||
        _arrowDirection == YCPopUpMenuBgViewArrowDirectionRight) {
        
        start = (CGPoint){X0, Y0};
        end = (CGPoint){X1, Y0};
        
    } else {
        
        start = (CGPoint){X0, Y0};
        end = (CGPoint){X0, Y1};
    }
    
    CGContextDrawLinearGradient(context, gradient, start, end, 0);
    
    CGGradientRelease(gradient);
}

@end

#pragma mark - YCPopUpMenuItemCell 

/**
 *  菜单单元格
 */
@interface YCPopUpMenuItemCell : UITableViewCell

@property (nonatomic, assign) BOOL hiddenImg;

@property (nonatomic, strong) UIImageView *titleImgView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIView *lineView;

@end

@implementation YCPopUpMenuItemCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self =[super initWithStyle:style reuseIdentifier:reuseIdentifier];
    
    if (self) {
        self.selectionStyle = UITableViewCellSelectionStyleNone;
        self.backgroundColor = [UIColor clearColor];
    }
    
    return self;
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (newSuperview) {
        [self addTitleImgView];
        [self addTitleLabel];
        [self addLineView];
    }
}

#pragma mark - Setter and Getter 

- (UIImageView *)titleImgView {
    if (_titleImgView == nil) {
        _titleImgView = [[UIImageView alloc] init];
        _titleImgView.backgroundColor = [UIColor clearColor];
    }
    
    return _titleImgView;
}

- (UILabel *)titleLabel {
    if (_titleLabel == nil) {
        _titleLabel = [[UILabel alloc] init];
        _titleLabel.backgroundColor = [UIColor clearColor];
        _titleLabel.textColor = [UIColor whiteColor];
        _titleLabel.font = [UIFont systemFontOfSize:kCellTitleFont];
    }
    
    return _titleLabel;
}

- (UIView *)lineView {
    if (_lineView == nil) {
        _lineView = [[UIView alloc] init];
        _lineView.backgroundColor = [UIColor whiteColor];
    }
    
    return _lineView;
}

#pragma mark - View Config

- (void)addTitleImgView {
    self.titleImgView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.contentView addSubview:self.titleImgView];
    
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleImgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:8.f]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleImgView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.f]];
    [self.titleImgView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleImgView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:(self.hiddenImg ? 0.f : 20.f)]];
    [self.titleImgView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleImgView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:20.f]];
}

- (void)addTitleLabel {
    self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.contentView addSubview:self.titleLabel];
    
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.titleImgView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:(self.hiddenImg ? 0.f : 8.f)]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.f]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-8.f]];
    [self.titleLabel addConstraint:[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:20.f]];
}

- (void)addLineView {
    self.lineView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.contentView addSubview:self.lineView];
    
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.lineView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.f]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.lineView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.f]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.lineView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.f]];
    [self.lineView addConstraint:[NSLayoutConstraint constraintWithItem:self.lineView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.5f]];
}

@end

#pragma mark - YCPopUpMenuVC

/**
 *  弹出的菜单所在的视图控制器
 */
@interface YCPopUpMenuVC : UIViewController<UITableViewDataSource, UITableViewDelegate> {
    UIWindow *_window;      /// 当前对话框所在的窗口
    UIWindow *_oldWindow;   /// 之前的窗口
    UIView *_focusView;                          /// 点击的控件
    NSArray<YCPopUpMenuItem *> *_tempActions;    /// 操作列表
}

/// 背景图
@property (strong, nonatomic) UIView *bgView;
/// 菜单视图
@property (strong, nonatomic) UIView *menuView;
/// 菜单视图
@property (strong, nonatomic) YCPopUpMenuBgView *menuBgView;
/// 菜单列表
@property (strong, nonatomic) UITableView *menuTableView;

@property (strong, nonatomic) NSLayoutConstraint *constraintMenuViewTop;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuViewLeading;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuViewWidth;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuViewHeight;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuTableViewTop;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuTableViewLeading;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuTableViewTrailing;
@property (strong, nonatomic) NSLayoutConstraint *constraintMenuTableViewBottom;

@end

@implementation YCPopUpMenuVC

#pragma mark - Life Cycle

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - View Config

/// 添加背景视图
- (void)addBgView {
    [self.view addSubview:self.bgView];
    
    self.bgView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.bgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.f]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.bgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.f]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.bgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.f]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.bgView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.f]];
}

/// 添加菜单列表视图
- (void)addMenuTableView {
    self.menuTableView.translatesAutoresizingMaskIntoConstraints = NO;
    self.menuTableView.dataSource = self;
    self.menuTableView.delegate = self;
    
    [self.menuView addSubview:self.menuTableView];
    
    self.constraintMenuTableViewTop = [NSLayoutConstraint constraintWithItem:self.menuTableView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeTop multiplier:1.0f constant:(self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionUp ? kArrowSize : 0.f)];
    self.constraintMenuTableViewLeading = [NSLayoutConstraint constraintWithItem:self.menuTableView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:(self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionLeft ? kArrowSize : 0.f)];
    self.constraintMenuTableViewTrailing = [NSLayoutConstraint constraintWithItem:self.menuTableView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:(self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionRight ? -kArrowSize : 0.f)];
    self.constraintMenuTableViewBottom = [NSLayoutConstraint constraintWithItem:self.menuTableView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:(self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionRight ? -kArrowSize : 0.f)];
    
    [self.menuView addConstraint:self.constraintMenuTableViewTop];
    [self.menuView addConstraint:self.constraintMenuTableViewLeading];
    [self.menuView addConstraint:self.constraintMenuTableViewTrailing];
    [self.menuView addConstraint:self.constraintMenuTableViewBottom];
}

/// 添加菜单背景
- (void)addMenuBgView {
    self.menuBgView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.menuView addSubview:self.menuBgView];
    
    [self.menuView addConstraint:[NSLayoutConstraint constraintWithItem:self.menuBgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.f]];
    [self.menuView addConstraint:[NSLayoutConstraint constraintWithItem:self.menuBgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.f]];
    [self.menuView addConstraint:[NSLayoutConstraint constraintWithItem:self.menuBgView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.f]];
    [self.menuView addConstraint:[NSLayoutConstraint constraintWithItem:self.menuBgView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.menuView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.f]];
}

/// 添加菜单视图
- (void)addMenuView {
    self.menuView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:self.menuView];
    
    // 必须要在添加子视图之前调用
    CGRect rect = [self menuViewFrame];
    self.menuView.frame = rect;
    
    self.constraintMenuViewTop = [NSLayoutConstraint constraintWithItem:self.menuView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:rect.origin.y];
    self.constraintMenuViewLeading = [NSLayoutConstraint constraintWithItem:self.menuView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:rect.origin.x];
    self.constraintMenuViewWidth = [NSLayoutConstraint constraintWithItem:self.menuView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:rect.size.width];
    self.constraintMenuViewHeight = [NSLayoutConstraint constraintWithItem:self.menuView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:rect.size.height];
    
    [self.view addConstraint:self.constraintMenuViewTop];
    [self.view addConstraint:self.constraintMenuViewLeading];
    [self.menuView addConstraint:self.constraintMenuViewWidth];
    [self.menuView addConstraint:self.constraintMenuViewHeight];
    
    [self addMenuBgView];
    [self addMenuTableView];
}

/// 刷新菜单视图
- (void)refreshMenuViewPosition {
    CGRect rect = [self menuViewFrame];
    self.menuView.frame = rect;
    
    self.constraintMenuViewTop.constant = rect.origin.y;
    self.constraintMenuViewLeading.constant = rect.origin.x;
    self.constraintMenuViewWidth.constant = rect.size.width;
    self.constraintMenuViewHeight.constant = rect.size.height;
    
    self.constraintMenuTableViewTop.constant = self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionUp ? kArrowSize : 0.f;
    self.constraintMenuTableViewLeading.constant = self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionLeft ? kArrowSize : 0.f;
    self.constraintMenuTableViewTrailing.constant = self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionRight ? -kArrowSize : 0.f;
    self.constraintMenuTableViewBottom.constant = self.menuBgView.arrowDirection==YCPopUpMenuBgViewArrowDirectionRight ? -kArrowSize : 0.f;
    
    [self.menuView layoutIfNeeded];
}

#pragma mark - Setter and Getter

- (UIView *)bgView {
    if (_bgView == nil) {
        _bgView = [[UIView alloc] init];
        _bgView.alpha = kMinMask;
        _bgView.backgroundColor = [UIColor clearColor];
        UITapGestureRecognizer*tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bgViewDidClick:)];
        [_bgView addGestureRecognizer:tapGesture];
    }
    
    return _bgView;
}

- (UIView *)menuView {
    if (_menuView == nil) {
        _menuView = [[UIView alloc] init];
        _menuView.backgroundColor = [UIColor clearColor];
        _menuView.opaque = YES;
        
        _menuView.layer.shadowOpacity = 0.5f;
        _menuView.layer.shadowOffset = CGSizeMake(2.f, 2.f);
        _menuView.layer.shadowRadius = 2.f;
    }
    
    return _menuView;
}

- (UIView *)menuBgView {
    if (_menuBgView == nil) {
        _menuBgView = [[YCPopUpMenuBgView alloc] init];
        _menuBgView.backgroundColor = [UIColor clearColor];
    }
    
    return _menuBgView;
}

- (UITableView *)menuTableView {
    if (_menuTableView == nil) {
        _menuTableView = [[UITableView alloc] init];
        _menuTableView.backgroundColor = [UIColor clearColor];
        _menuTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _menuTableView.tableFooterView = [[UIView alloc] init];
    }
    
    return _menuTableView;
}

#pragma mark - Private Methods

/// 获取菜单列表宽度
- (CGFloat)menuWidth {
    CGFloat menuWith = 16.f;
    // 增加图片宽度
    for (YCPopUpMenuItem *item in _tempActions) {
        if (item.img) {
            // 增加图片宽度
            menuWith += 20.f;
            // 增加间隔
            menuWith += 8.f;
            break;
        }
    }
    // 增加字体宽度
    CGFloat maxStrWidth = 0.f;
    for (YCPopUpMenuItem *item in _tempActions) {
        if (item.title) {
            maxStrWidth = fmaxf(maxStrWidth, [self widthOfStr:item.title]);
        }
    }
    menuWith += maxStrWidth;
    
    return menuWith;
}

- (CGFloat)widthOfStr:(NSString *)str {
    return [str sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kCellTitleFont]}].width + 0.5f;
}

/// 获取菜单的位置和大小
- (CGRect)menuViewFrame {
    CGRect focusViewFrameInWindow = [_focusView.superview convertRect:_focusView.frame toView:_focusView.window];
    
    const CGFloat menuWith_need = [self menuWidth];
    const CGFloat windowWidth = [UIScreen mainScreen].bounds.size.width;
    const CGFloat windowHeight = [UIScreen mainScreen].bounds.size.height;
    const CGFloat margin = 8.f;
    const CGFloat menuHeight_need = _tempActions.count * kCellHeight;
    
    const CGFloat focusViewCenterX = focusViewFrameInWindow.origin.x + focusViewFrameInWindow.size.width/2.f;
    const CGFloat focusViewCenterY = focusViewFrameInWindow.origin.y + focusViewFrameInWindow.size.height/2.f;
    
    CGRect menuRect = CGRectMake(0.f, 0.f, 0.f, 0.f);
    
    if (menuHeight_need < windowHeight - focusViewFrameInWindow.origin.y - focusViewFrameInWindow.size.height - margin - kArrowSize) {
        self.menuBgView.arrowDirection = YCPopUpMenuBgViewArrowDirectionUp;
        
        // 计算菜单视图位置和大小
        CGFloat menuHeight_real = menuHeight_need + kArrowSize;
        CGFloat menuWidth_real = menuWith_need;
        if (menuWidth_real + margin + margin > windowWidth) {
            menuWidth_real = windowWidth- margin - margin;
            
            menuRect = CGRectMake(margin, focusViewFrameInWindow.origin.y + focusViewFrameInWindow.size.height, menuWidth_real, menuHeight_real);
        } else {
            if (focusViewCenterX < margin + menuWidth_real/2.f) {
                menuRect = CGRectMake(margin, focusViewFrameInWindow.origin.y + focusViewFrameInWindow.size.height, menuWidth_real, menuHeight_real);
            } else if (focusViewCenterX > windowWidth - margin - menuWidth_real/2.f) {
                menuRect = CGRectMake(windowWidth - margin - menuWidth_real, focusViewFrameInWindow.origin.y + focusViewFrameInWindow.size.height, menuWidth_real, menuHeight_real);
            } else {
                menuRect = CGRectMake(focusViewCenterX - menuWidth_real/2.f, focusViewFrameInWindow.origin.y + focusViewFrameInWindow.size.height, menuWidth_real, menuHeight_real);
            }
        }
        // 计算箭头位置
        self.menuBgView.arrowPosition = focusViewCenterX - menuRect.origin.x;
    } else if (menuHeight_need < focusViewFrameInWindow.origin.y - margin - kArrowSize) {
        self.menuBgView.arrowDirection = YCPopUpMenuBgViewArrowDirectionDown;
        
        // 计算菜单视图位置和大小
        CGFloat menuHeight_real = menuHeight_need + kArrowSize;
        CGFloat menuWidth_real = menuWith_need;
        if (menuWidth_real + margin + margin > windowWidth) {
            menuWidth_real = windowWidth- margin - margin;
            
            menuRect = CGRectMake(margin, focusViewFrameInWindow.origin.y - menuHeight_real, menuWidth_real, menuHeight_real);
        } else {
            if (focusViewCenterX < margin + menuWidth_real/2.f) {
                menuRect = CGRectMake(margin, focusViewFrameInWindow.origin.y - menuHeight_real, menuWidth_real, menuHeight_real);
            } else if (focusViewCenterX > windowWidth - margin - menuWidth_real/2.f) {
                menuRect = CGRectMake(windowWidth-margin-menuWidth_real, focusViewFrameInWindow.origin.y - menuHeight_real, menuWidth_real, menuHeight_real);
            } else {
                menuRect = CGRectMake(focusViewCenterX - menuWidth_real/2.f, focusViewFrameInWindow.origin.y - menuHeight_real, menuWidth_real, menuHeight_real);
            }
        }
        // 计算箭头位置
        self.menuBgView.arrowPosition = focusViewCenterX - menuRect.origin.x;
    } else {
        if (menuWith_need < windowWidth - focusViewFrameInWindow.origin.x - focusViewFrameInWindow.size.width - margin - kArrowSize) {
            self.menuBgView.arrowDirection = YCPopUpMenuBgViewArrowDirectionLeft;
            
            // 计算菜单视图位置和大小
            CGFloat menuWidth_real = menuWith_need + kArrowSize;
            CGFloat menuHeight_real = menuHeight_need;
            if (menuHeight_need + margin + margin > windowHeight) {
                menuHeight_real = windowHeight - margin - margin;
                
                menuRect = CGRectMake(focusViewFrameInWindow.origin.x + focusViewFrameInWindow.size.width, margin, menuWidth_real, menuHeight_real);
            } else {
                if (focusViewCenterY < margin + menuHeight_real/2.f) {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x + focusViewFrameInWindow.size.width, margin, menuWidth_real, menuHeight_real);
                } else if (focusViewCenterY > windowHeight - margin - menuHeight_real/2.f) {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x + focusViewFrameInWindow.size.width, windowHeight - margin - menuHeight_real, menuWidth_real, menuHeight_real);
                } else {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x + focusViewFrameInWindow.size.width, focusViewCenterY - menuHeight_real/2.f, menuWidth_real, menuHeight_real);
                }
            }
            // 计算箭头位置
            self.menuBgView.arrowPosition = focusViewCenterY - menuRect.origin.y;
        } else if (menuWith_need < focusViewFrameInWindow.origin.x - kArrowSize - margin) {
            self.menuBgView.arrowDirection = YCPopUpMenuBgViewArrowDirectionRight;
            
            // 计算菜单视图位置和大小
            CGFloat menuWidth_real = menuWith_need + kArrowSize;
            CGFloat menuHeight_real = menuHeight_need;
            if (menuHeight_need + margin + margin > windowHeight) {
                menuHeight_real = windowHeight - margin - margin;
                
                menuRect = CGRectMake(focusViewFrameInWindow.origin.x - menuWidth_real, margin, menuWidth_real, menuHeight_real);
            } else {
                if (focusViewCenterY < margin + menuHeight_real/2.f) {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x - menuWidth_real, margin, menuWidth_real, menuHeight_real);
                } else if (focusViewCenterY > windowHeight - margin - menuHeight_real/2.f) {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x - menuWidth_real, windowHeight - margin - menuHeight_real, menuWidth_real, menuHeight_real);
                } else {
                    menuRect = CGRectMake(focusViewFrameInWindow.origin.x - menuWidth_real, focusViewCenterY - menuHeight_real/2.f, menuWidth_real, menuHeight_real);
                }
            }
            // 计算箭头位置
            self.menuBgView.arrowPosition = focusViewCenterY - menuRect.origin.y;
        } else {
            self.menuBgView.arrowDirection = YCPopUpMenuBgViewArrowDirectionNone;
            
            // 计算菜单视图位置和大小
            CGFloat menuWidth_real = menuWith_need;
            CGFloat menuHeight_real = menuHeight_need;
            if (menuWidth_real + margin + margin > windowWidth) {
                menuWidth_real = windowWidth - margin - margin;
            }
            if (menuHeight_real + margin + margin > windowHeight) {
                menuHeight_real = windowHeight - margin - margin;
            }
            
            menuRect = CGRectMake(windowWidth/2.f, windowHeight/2.f, menuWidth_real, menuHeight_real);
        }
    }
    
    return menuRect;
}

#pragma mark - Event Response

- (void)bgViewDidClick:(UIView *)view {
    [self dismiss];
}

#pragma mark - Observer

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if (object == _focusView) {
        if ([keyPath isEqualToString:@"center"]) {
            static CGPoint pointOld;
            
            CGPoint pointNew = [_focusView.superview convertPoint:[change[NSKeyValueChangeNewKey] CGPointValue] toView:_focusView.window];
            
            if (!CGPointEqualToPoint(pointOld, pointNew)) {
                pointOld = pointNew;
                
                [self refreshMenuViewPosition];
            }
        } else {
            static CGRect rectOld;
            
            CGRect rectNew = [_focusView.superview convertRect:[change[NSKeyValueChangeNewKey] CGRectValue] toView:_focusView.window];
            
            if (!CGRectEqualToRect(rectOld, rectNew)) {
                rectOld = rectNew;
                
                [self refreshMenuViewPosition];
            }
        }
    }
}

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _tempActions.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self createCellItemInTableView:tableView atIndexPath:indexPath];
}

- (UITableViewCell *)createCellItemInTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
    YCPopUpMenuItemCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellItem"];
    if (cell == nil) {
        cell = [[YCPopUpMenuItemCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cellItem"];
    }
    
    YCPopUpMenuItem *item = _tempActions[indexPath.row];

    UIImage *img = item.img;
    cell.titleImgView.image = img;
    if (img) {
        cell.hiddenImg = NO;
    } else {
        cell.hiddenImg = YES;
    }
    cell.titleLabel.text = item.title;
    cell.titleLabel.textColor = item.titleColor;
    cell.lineView.hidden = indexPath.row == _tempActions.count-1;
    
    return cell;
}

#pragma mark - UITableViewDelegate

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 0.f;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return kCellHeight;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self dismiss];
    
    [_tempActions[indexPath.section] performAction];
}

#pragma mark - Animation

/// 对话框出现动画
- (void)showAnimation {
    [UIView animateWithDuration:kAnimationDuration animations:^{
        self.bgView.alpha = kMaxMask;
    } completion:^(BOOL finished) {
        
    }];
    
    CAKeyframeAnimation *popAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    popAnimation.duration = kAnimationDuration;
    popAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.01f, 0.01f, 1.0f)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1f, 1.1f, 1.0f)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9f, 0.9f, 0.9f)],
                            [NSValue valueWithCATransform3D:CATransform3DIdentity]];
    popAnimation.keyTimes = @[@0.2f, @0.5f, @0.75f, @1.0f];
    popAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [self.menuView.layer addAnimation:popAnimation forKey:nil];
}

/// 对话框消失动画
- (void)dismissAnimation {
    [UIView animateWithDuration:kAnimationDuration animations:^{
        self.bgView.alpha = kMinMask;
        self.menuView.alpha = 0.0;
    } completion:^(BOOL finished) {
        [_window resignKeyWindow];
        [_oldWindow resignKeyWindow];
        
        _window = nil;
    }];
}

#pragma mark - Control

/// 显示对话框
- (void)showFromView:(UIView *)view actions:(NSArray<YCPopUpMenuItem *> *)actions {
    _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    _window.windowLevel = 440.f;
    _window.rootViewController = self;
    _oldWindow = [UIApplication sharedApplication].keyWindow;
    [_window makeKeyAndVisible];
    
    _focusView = view;
    [_focusView addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:nil];
    [_focusView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];
    
    _tempActions = actions;
    
    [self addBgView];
    [self addMenuView];
    
    [self showAnimation];
}

/// 隐藏对话框
- (void)dismiss {
    [_focusView removeObserver:self forKeyPath:@"center"];
    [_focusView removeObserver:self forKeyPath:@"frame"];
    
    [self dismissAnimation];
}

@end


#pragma mark - YCPopUpMenu

@interface  YCPopUpMenu () {
    YCPopUpMenuVC *_menuVC;             /// 菜单
    BOOL _isObservingOrientation;       /// 是否在监听屏幕旋转
}

@end

@implementation YCPopUpMenu

- (void)showFromView:(UIView *)view menuItems:(NSArray<YCPopUpMenuItem *> *)menuItems {
    _menuVC = [[YCPopUpMenuVC alloc] init];
    
    [_menuVC showFromView:view actions:menuItems];
}

- (void)dismiss {
    [_menuVC dismiss];
}

@end
